#include<iostream>
#include<unistd.h>//pipe,fork
#include<sys/types.h>//fork,waitpid
#include<sys/wait.h>//waitpid
#include<cstring>
void ChildWrite(int wfd)
{
    char buffer[1024];//要写入管道中的数据的暂存数组
    int cnt = 0;//记录for循环的执行次数
    while(true)
    {
        snprintf(buffer,sizeof buffer,"I am child , pid:%d , cnt=%d",getpid(),cnt++);//将字符串中的数据格式化到buffer数组中。
        write(wfd,buffer,strlen(buffer));//将buffer的能容写入到wfd指向的文件中。
        sleep(1);//每隔一秒执行一次while循环,方便观察
    }
}
void FatherRead(int rfd)
{
    char buffer[1024];//存储从管道中读取到的文件
    while(true)
    {
        memset(buffer,0,sizeof(buffer));//将数组置空
        size_t n = read(rfd,buffer,sizeof (buffer) - 1);//将管道中的数据读取到buffer数组中,并空出一位用于添加'\0'
        if(n > 0)
        {
            buffer[n] = 0;//为数组末尾添加上'\0',c语言中处理字符串的函数一般会自动加上'\0',而系统调用需要手动添加;
            std::cout  << "child say:" << buffer << std::endl;
        }
    }
}
int main()
{
    //创建管道
    int fds[2] = {0};//fds[0]:r , fds[1]:w
    int n = pipe(fds);//管道创建成功返回0，失败返回-1并设置错误码
    if(n < 0)
    {
        //创建管道失败
        std::cerr << "pipe error" << std::endl; //打印创建失败的错误原因
        return 1;//返回一个错误码
    }
    //测试一下管道是否真的可以以文件的形式打开
    //std::cout << "fds[0]:" << fds[0] << std::endl;//3
    //std::cout << "fds[1]:" << fds[1] << std::endl;//4

    //创立好管道后，创建子进程
    pid_t id =  fork();//在父进程中返回子进程的pid，在子进程中返回0，错误时返回负值
    if(id == 0)
    {
        //子进程创建成功,关闭不需要的读写功能,形成通信的信道
        close(fds[0]);//关闭子进程读的功能
        ChildWrite(fds[1]);//模拟子进程向文件中写入的场景
        close(fds[1]);//子进程写入完毕,将子进程的写功能也关闭
        return 0;//结束子进程
    }
    //父进程代码
    close(fds[1]);//关闭父进程的写功能;
    FatherRead(fds[0]);//模拟父进程读取管道中的数据
    waitpid(id,nullptr,0);//父进程采用阻塞等待的方式等待,id子进程结束
    close(fds[0]);//关闭父进程的读功能
    return 0;
}